﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Web.Mvc;
using Xenta.Utils;
using Xenta.Attributes;
using Xenta.Web.Controllers;

namespace Xenta.Web.Areas.Commerce.Controllers
{
    [Authenticate, InRole("ADMIN")]
    public sealed class OrderController : ExtController
    {
        #region GET/POST Actions

        [HttpGet]
        public ActionResult Index()
        {
            return View();
        }

        [HttpGet]
        public ActionResult GoTo(int? id, string guid)
        {
            if(!id.HasValue)
            {
                dynamic m = null;
                if(!String.IsNullOrWhiteSpace(guid))
                {
                    m = Svc.ProcessOperation("GetOrderByGuid", new
                    {
                        Guid = guid.ParseAs<Guid>()
                    });
                }
                if(m == null)
                    return HttpNotFound();
                id = JDM.Int32(m.EntityID);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id
            }));
        }

        [HttpGet, RestoreState]
        public ActionResult Create()
        {
            return View();
        }

        [HttpPost, PersistState]
        public ActionResult Create(Guid shippingMethodID,
            Guid salesModelID,
            int customerID, 
            int sellerID,
            int sellerAddressID,
            int billingAddressID,
            int shippingAddressID,
            string handlingFee,
            string taxAmount,
            string discountAmount,
            string shippingPrice,
            string subtotal,
            string total,
            string[] flags)
        {
            try
            {
                var m = Svc.ProcessOperation("CreateOrder", new
                {
                    CustomerID = customerID,
                    ShippingMethodID = shippingMethodID,
                    SalesModelID = salesModelID,
                    SellerID = sellerID,
                    SellerAddressID = sellerAddressID,
                    BillingAddressID = billingAddressID,
                    ShippingAddressID = shippingAddressID,
                    HandlingFee = Svc.Price(handlingFee),
                    TaxAmount = Svc.Price(taxAmount),
                    DiscountAmount = Svc.Price(discountAmount),
                    ShippingPrice = Svc.Price(shippingPrice),
                    Subtotal = Svc.Price(subtotal),
                    Total = Svc.Price(total),
                    Flags = flags.Merge(",")
                });
                return RedirectToAction(Loc.Act("Edit").Set(new
                {
                    id = JDM.Int32(m.EntityID)
                }));
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Create"));
        }

        [HttpGet, RestoreState]
        public ActionResult Edit(int id)
        {
            var m = Svc.ProcessOperation("GetOrder", new
            {
                EntityID = id,
                Fetch = "Entire"
            }, new
            {
                DisclosureLevel = "Entire"
            });
            if(m == null)
                return HttpNotFound();
            return View(m);
        }

        [HttpPost, PersistState]
        public ActionResult Update(int id,
            string handlingFee,
            string taxAmount,
            string discountAmount,
            string shippingPrice,
            string subtotal,
            string total,
            string[] flags)
        {
            try
            {
                Svc.ProcessOperation("UpdateOrder", new
                {
                    EntityID = id,
                    HandlingFee = Svc.Price(handlingFee),
                    TaxAmount = Svc.Price(taxAmount),
                    DiscountAmount = Svc.Price(discountAmount),
                    ShippingPrice = Svc.Price(shippingPrice),
                    Subtotal = Svc.Price(subtotal),
                    Total = Svc.Price(total),
                    Flags = flags.Merge(",")
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }

            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id
            }));
        }

        [HttpGet, RestoreState]
        public ActionResult Delete(int id)
        {
            try
            {
                Svc.ProcessOperation("DeleteOrder", new
                {
                    EntityID = id
                });
                return RedirectToAction(Loc.Act("Index"));
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id
            }));
        }

        [HttpGet, RestoreState]
        public ActionResult Cancel(int id)
        {
            try
            {
                Svc.ProcessOperation("CancelOrder", new
                {
                    EntityID = id
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id
            }));
        }

        [HttpGet, RestoreState]
        public ActionResult Issue(int id)
        {
            try
            {
                Svc.ProcessOperation("IssueOrder", new
                {
                    EntityID = id
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id
            }));
        }

        [HttpGet, RestoreState]
        public ActionResult Confirm(int id)
        {
            try
            {
                Svc.ProcessOperation("ConfirmOrder", new
                {
                    EntityID = id
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id
            }));
        }

        [HttpGet, RestoreState]
        public ActionResult Process(int id)
        {
            try
            {
                Svc.ProcessOperation("ProcessOrder", new
                {
                    EntityID = id
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id
            }));
        }

        [HttpGet, RestoreState]
        public ActionResult Complete(int id)
        {
            try
            {
                Svc.ProcessOperation("CompleteOrder", new
                {
                    EntityID = id
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id
            }));
        }

        [HttpPost, PersistState]
        public ActionResult CreateOrderItem(int orderID,
            string sku,
            string quantity,
            string price,
            string taxAmount,
            string discountAmount,
            string subtotal,
            string total,
            string[] flags)
        {
            try
            {
                Svc.ProcessOperation("CreateOrderItem", new
                {
                    OrderID = orderID,
                    SKU = sku,
                    Price = Svc.Price(price),
                    Quantity = Svc.Numeric(quantity),
                    TaxAmount = Svc.Price(taxAmount),
                    DiscountAmount = Svc.Price(discountAmount),
                    Subtotal = Svc.Price(subtotal),
                    Total = Svc.Price(total),
                    Flags = flags.Merge(",")
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id = orderID
            }));
        }

        [HttpPost, PersistState]
        public ActionResult UpdateOrderItem(int id,
            int orderID,
            string sku,
            string quantity,
            string price,
            string taxAmount,
            string discountAmount,
            string subtotal,
            string total,
            string[] flags)
        {
            try
            {
                Svc.ProcessOperation("UpdateOrderItem", new
                {
                    EntityID = id,
                    OrderID = orderID,
                    Price = Svc.Price(price),
                    Quantity = Svc.Numeric(quantity),
                    TaxAmount = Svc.Price(taxAmount),
                    DiscountAmount = Svc.Price(discountAmount),
                    Subtotal = Svc.Price(subtotal),
                    Total = Svc.Price(total),
                    Flags = flags.Merge(",")
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id = orderID
            }));
        }

        [HttpGet, PersistState]
        public ActionResult DeleteOrderItem(int id, int orderID)
        {
            try
            {
                Svc.ProcessOperation("DeleteOrderItem", new
                {
                    EntityID = id
                });
                return RedirectToAction(Loc.Act("Index"));
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }
            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id = orderID
            }));
        }

        [HttpPost, PersistState]
        public ActionResult BulkAttributeUpdate(int orderID, IDictionary<String, String> attributes)
        {
            try
            {
                Svc.ProcessOperation("BulkUpdateOrderAttributes", new
                {
                    HolderID = orderID,
                    Attributes = attributes
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }

            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id = orderID
            }));
        }

        [HttpPost, PersistState]
        public ActionResult BulkItemAttributeUpdate(int itemID, int orderID, IDictionary<String, String> attributes)
        {
            try
            {
                Svc.ProcessOperation("BulkUpdateOrderItemAttributes", new
                {
                    HolderID = itemID,
                    Attributes = attributes
                });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("API", ex);
            }

            return RedirectToAction(Loc.Act("Edit").Set(new
            {
                id = orderID
            }));
        }

        #endregion

        #region Child Actions

        [ChildActionOnly]
        public ActionResult _Comments(int orderID)
        {
            dynamic m = new ExpandoObject();

            m.EntityID = orderID;
            m.Comments = Svc.ProcessOperation("SearchOrderComments", new
            {
                HolderID = orderID
            }, new
            {
                DisclosureLevel = "Extended"
            }).Items;
            return PartialView(m);
        }

        #endregion

        #region AJAX Actions

        [HttpPost]
        public ActionResult Grid(int? page,
            int? rows,
            string sord,
            string sidx,
            int? customerID,
            int? sellerID,
            string createdFrom,
            string createdTo,
            string flagMask)
        {
            page = page.HasValue ? page.Value - 1 : 0;
            rows = rows.HasValue ? rows.Value : 30;
            sord = sord.Equals("desc") ? "Descending" : "Ascending";

            var m = Svc.ProcessOperation("SearchOrders", new 
            {
                CustomerID = customerID,
                SellerID = sellerID,
                FlagMask = flagMask,
                CreatedFrom = String.IsNullOrWhiteSpace(createdFrom) 
                    ? (DateTime?)null 
                    : Svc.DateTime(createdFrom),
                CreatedTo = String.IsNullOrWhiteSpace(createdTo) 
                    ? (DateTime?)null 
                    : Svc.DateTime(createdTo),
                Index = page * rows,
                Count = rows,
                SortBy = new[] 
                {
                    sidx
                },
                SortDir = sord
            }, new
            {
                DisclosureLevel = "Base"
            });
            var data = new List<Object>();

            foreach(var i in m.Items)
            {
                string status = String.Empty;

                if(JDM.HasFlags(i.Flags, "Canceled"))
                    status = Svc.Translate(Res.In("API").Of("Enum").Of("OrderFlags").Name("Canceled"));
                else if(JDM.HasFlags(i.Flags, "Pending"))
                    status = Svc.Translate(Res.In("API").Of("Enum").Of("OrderFlags").Name("Pending"));
                else if(JDM.HasFlags(i.Flags, "Confirmed"))
                    status = Svc.Translate(Res.In("API").Of("Enum").Of("OrderFlags").Name("Confirmed"));
                else if(JDM.HasFlags(i.Flags, "Processing"))
                    status = Svc.Translate(Res.In("API").Of("Enum").Of("OrderFlags").Name("Processing"));
                else if(JDM.HasFlags(i.Flags, "Completed"))
                    status = Svc.Translate(Res.In("API").Of("Enum").Of("OrderFlags").Name("Completed"));

                data.Add(new[] { 
                    JDM.Int32(i.EntityID),
                    JDM.String(i.Customer.Account.Email),
                    JDM.String(i.Seller.Account.Email),
                    Svc.Price((decimal)JDM.Decimal(i.Total)),
                    status,
                    Svc.DateTime((DateTime)JDM.DateTime(i.CreatedOn))
                });
            }

            return Json(new
            {
                pageIndex = page + 1,
                pageCount = Math.Ceiling(JDM.Double(m.TotalCount) / rows),
                totalCount = JDM.Int64(m.TotalCount),
                data = data.ToArray()
            });
        }

        [HttpPost]
        public ActionResult SalesModels()
        {
            dynamic m = Svc.ProcessOperation("ListSalesModel");
            var data = new List<Object>();

            foreach(var i in m)
            {
                data.Add(new
                {
                    id = JDM.Guid(i.ID),
                    value = JDM.String(i.Name)
                });
            }
            return Json(data.ToArray());
        }

        [HttpPost]
        public ActionResult ShippingMethods()
        {
            dynamic m = Svc.ProcessOperation("ListShippingMethods");
            var data = new List<Object>();

            foreach(var i in m)
            {
                data.Add(new
                {
                    id = JDM.Guid(i.ID),
                    value = JDM.String(i.Name)
                });
            }
            return Json(data.ToArray());
        }

        #endregion
    }
}
